package tema10.persistence;

import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import tema10.model.Contacto;

public class ContactoDAOJDBCImplementation implements ContactoDAO{
    
    private final Object lockOfConnection = new Object();
    private Connection conexion = null;
    private static ContactoDAOJDBCImplementation persistenceManager = null;
    private static final Logger logger = Logger.getLogger(ContactoDAOJDBCImplementation.class.getName());
    
    ContactoDAOJDBCImplementation() {      
    }

    public static ContactoDAOJDBCImplementation getContactoDAOJDBCImplementation() {
        if(persistenceManager == null)
            persistenceManager = new ContactoDAOJDBCImplementation();
        
        return persistenceManager;
    }

    @Override
    public boolean createContacto(Contacto contacto) {
        String query = "insert into CONTACTOS values(?,?,?,?,?,?)";
        PreparedStatement statement;
        try{
            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1,contacto.getIdAsString());
            statement.setString(2,contacto.getNombre());
            statement.setString(3,contacto.getApellidos());
            statement.setString(4,contacto.getTelefono());
            statement.setDate(5,contacto.getFechaNacimientoAsSQLDate());
            statement.setString(6,contacto.getInformacion());
            //logger.log(Level.INFO, "Creando contacto: {0} {1} {2} {3} {4} {5}",
            //new Object[]{contacto.getIdAsString(), contacto.getNombre(), contacto.getApellidos(),
            //contacto.getTelefono(), contacto.getFechaNacimiento(), contacto.getInformacion()});
            statement.execute();
            return true;
        } catch (SQLException ex) {
            logger.log(Level.SEVERE,  "Error al crear un contacto", ex);
            return false;
        }
    }

    @Override
    public Contacto readContacto(String id) {
        String query = "select * from CONTACTOS where ID =?";
        PreparedStatement statement;
        ResultSet resultSet = null;
        Contacto contacto = null;
        try {
            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1, id);
            resultSet = statement.executeQuery();
            if (resultSet.next()) {
                contacto = new Contacto(resultSet.getString("ID"));
                contacto.setNombre(resultSet.getString("NOMBRE"));
                contacto.setApellidos(resultSet.getString("APELLIDOS"));
                contacto.setTelefono(resultSet.getString("TELEFONO"));
                contacto.setFechaNacimientoFromLong(resultSet.getDate("FECHANACIMIENTO").getTime());
                contacto.setInformacion(resultSet.getString("INFORMACION"));
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al recuperar un contacto", ex);
            contacto = null;
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ex) {
                    logger.log(Level.SEVERE, "Error al cerrar la conexon a la base de datos", ex);
                }
            }
        }
        return contacto;
    }
    
    @Override
    public Contacto readContacto(String nombre, String apellidos) {
        String query = "select * from CONTACTOS where NOMBRE =? AND APELLIDOS=?";
        PreparedStatement statement;
        ResultSet resultSet = null;
        Contacto contacto = null;
        try {
            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1, nombre);
            statement.setString(2, apellidos);
            resultSet = statement.executeQuery();
            if (resultSet.next()) {
                //contacto = this.readContacto(resultSet.getString("ID"));
                contacto = new Contacto(resultSet.getString("ID"));
                contacto.setNombre(resultSet.getString("NOMBRE"));
                contacto.setApellidos(resultSet.getString("APELLIDOS"));
                contacto.setTelefono(resultSet.getString("TELEFONO"));
                contacto.setFechaNacimientoFromLong(resultSet.getDate("FECHANACIMIENTO").getTime());
                contacto.setInformacion(resultSet.getString("INFORMACION"));
            } else {
                return null;
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al recuperar un contacto", ex);
            contacto = null;
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ex) {
                    logger.log(Level.SEVERE, "Error al cerrar la conexon a la base de datos", ex);
                }
            }
        }
        return contacto;
    }

    @Override
    public boolean updateContacto(String id, Contacto contacto) {
        String query = null;
        query = "update CONTACTOS SET NOMBRE =?,APELLIDOS = ?,TELEFONO = ?,"
                + "FECHANACIMIENTO = ?, INFORMACION = ? where ID = ?";
        PreparedStatement statement;
        try {
            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1, contacto.getNombre());
            statement.setString(2, contacto.getApellidos());
            statement.setString(3, contacto.getTelefono());
            statement.setDate(4,contacto.getFechaNacimientoAsSQLDate());
            statement.setString(5, contacto.getInformacion());
            statement.setString(6, id);
            statement.execute();
            return true;
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al actualizar un amigo", ex);
            return false;
        }
    }

    @Override
    public boolean deleteContacto(String id) {
        String query = "delete from CONTACTOS where ID = ?";
        PreparedStatement statement;
        try {
            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1, id);
            statement.execute();
            return true;
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al borrar un contacto", ex);
            return false;
        }
    }

    @Override
    public String searchIDContacto(String nombre, String apellidos) {
        String query = "select ID from CONTACTOS where nombre =? AND apellidos=?";
        PreparedStatement statement;
        ResultSet resultSet = null;
        String id = null;
        try {
            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            statement.setString(1, nombre);
            statement.setString(2, apellidos);
            resultSet = statement.executeQuery();
            if (resultSet.next()) {
                id = resultSet.getString("ID");
            } else {
                return null;
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al recuperar un contacto", ex);
            id = null;
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ex) {
                    logger.log(Level.SEVERE, "Error al cerrar la conexon a la base de datos", ex);
                }
            }
        }
        return id;
    }

    @Override
    public boolean setUp(String url, String driver, String user, String password) {
        try {
            Class.forName(driver);
            conexion = DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException ex) {
            logger.log(Level.SEVERE, "No se encontro el driver para la base de datos", ex);
            return false;
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "No se pudo establecer la conexion con la base de datos", ex);
            return false;
        }
        return true;
    }

    @Override
    public boolean disconnect() {
        try {
            conexion.close();
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Conexión a la base de datos no cerrada", ex);
            return false;
        }
        return true;
    }
    
    //Para establecer conexiones en el ContactoDAOPoolImplementation mediante esta clase
    public void setConnection(Connection conexion) {
        synchronized (lockOfConnection) {
            this.conexion = conexion;
        }
    }
    
    /**
     * Lista los contactos dados unos parametros de busqueda
     * @param nombre null si no se ha de tener en cuenta
     * @param apellidos null si no se ha de tener en cuenta
     * @param telefono null si no se ha de tener en cuenta
     * @param dia 0 si no se ha de tener en cuenta
     * @param mes 0 si no se ha de tener en cuenta
     * @param anho 0 si no se ha de tener en cuenta
     * @return listado
     */
    @Override
    public ArrayList listContactos(String nombre, String apellidos, String telefono, int dia, int mes, int anho) {
        ArrayList<Contacto> listado = new ArrayList();
        //String query = "select * from \"CONTACTOS\" where NOMBRE =? AND APELLIDOS =? AND TELEFONO =? AND FECHANACIMIENTO =?";
        String query = "select * from CONTACTOS";
        PreparedStatement statement;
        ResultSet resultSet = null;
        Contacto contacto = null;
        int posNombre=1, posApellidos=2, posTelefono=3, posFechaNacimiento=4;
        boolean whereEscrito = false;
        
        try {
            if (nombre != null) {
                query = query.concat(" where");
                whereEscrito = true;
                query = query.concat(" NOMBRE =?");
            } else {
                posNombre = 0;
                posApellidos--;
                posTelefono--;
                posFechaNacimiento--;
            }
            if (apellidos != null) {
                if (!whereEscrito) {
                    query = query.concat(" where");
                    whereEscrito = true;
                } else {
                    query = query.concat(" AND");
                }
                query = query.concat(" APELLIDOS =?");
            } else {
                posApellidos = 0;
                posTelefono--;
                posFechaNacimiento--;
            }
            if (telefono != null) {
                if (!whereEscrito) {
                    query = query.concat(" where");
                    whereEscrito = true;
                } else {
                    query = query.concat(" AND");
                }
                query = query.concat(" TELEFONO =?");
            } else {
                posTelefono = 0;
                posFechaNacimiento--;
            }
            if(dia!=0 && mes!=0 && anho!=0) {
                if (!whereEscrito) {
                    query = query.concat(" where");
                    whereEscrito = true;
                } else {
                    query = query.concat(" AND");
                }
                query = query.concat(" FECHANACIMIENTO =?");
            } else {
                posFechaNacimiento = 0;
            }

            synchronized (lockOfConnection) {
                statement = conexion.prepareStatement(query);
            }
            if (posNombre != 0) {
                statement.setString(posNombre, nombre);
            }
            if (posApellidos != 0) {
                statement.setString(posApellidos, apellidos);
            }
            if (posTelefono != 0) {
                statement.setString(posTelefono, telefono);
            }
            if(posFechaNacimiento != 0) {
                Calendar fechaNacimiento = Calendar.getInstance();
                fechaNacimiento.clear();
                fechaNacimiento.set(anho, mes, dia);
                statement.setDate(posFechaNacimiento,new Date(fechaNacimiento.getTimeInMillis()));
            } 
            resultSet = statement.executeQuery();
            while (resultSet.next()) {
                //contacto = this.readContacto(resultSet.getString("ID"));
                contacto = new Contacto(resultSet.getString("ID"));
                contacto.setNombre(resultSet.getString("NOMBRE"));
                contacto.setApellidos(resultSet.getString("APELLIDOS"));
                contacto.setTelefono(resultSet.getString("TELEFONO"));
                contacto.setFechaNacimientoFromLong(resultSet.getDate("FECHANACIMIENTO").getTime());
                contacto.setInformacion(resultSet.getString("INFORMACION"));
                listado.add(contacto);
            }
        } catch (SQLException ex) {
            logger.log(Level.SEVERE, "Error al recuperar un contacto", ex);
            contacto = null;
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException ex) {
                    logger.log(Level.SEVERE, "Error al cerrar la conexon a la base de datos", ex);
                }
            }
        }
        
        return listado;
    }

}
